home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / rip.c < prev    next >
C/C++ Source or Header  |  1992-05-14  |  17KB  |  690 lines

  1. /* @(#) $Header: rip.c,v 1.6 92/05/14 13:20:25 deyke Exp $ */
  2.  
  3. /* This file contains code to implement the Routing Information Protocol (RIP)
  4.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  5.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  6.  * credited. (Well, here's some credit :-). AGB 4-28-88
  7.  
  8.  * Further documentation on the RIP protocol is now available in Charles
  9.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  10.  *
  11.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  12.  *
  13.  * Code gutted and substantially rewritten. KA9Q 9/89
  14.  */
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "netuser.h"
  18. #include "udp.h"
  19. #include "timer.h"
  20. #include "iface.h"
  21. #include "ip.h"
  22. #include "internet.h"
  23. #include "rip.h"
  24. #include "arp.h"
  25.  
  26. struct rip_stat Rip_stat;
  27. int16 Rip_trace;
  28. int Rip_merge;
  29. struct rip_list *Rip_list;
  30. struct udp_cb *Rip_cb;
  31.  
  32. struct rip_refuse *Rip_refuse;
  33.  
  34. static void rip_rx __ARGS((struct iface *iface,struct udp_cb *sock,int cnt));
  35. static void proc_rip __ARGS((struct iface *iface,int32 gateway,
  36.     struct rip_route *ep,int32 ttl));
  37. static char *putheader __ARGS((char *cp,int command,int version));
  38. static char *putentry __ARGS((char *cp,int fam,int32 target,int32 metric));
  39. static void rip_shout __ARGS((void *p));
  40. static void send_routes __ARGS((int32 dest,int port,int split,int trig,
  41.     int us));
  42.  
  43. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  44. static void
  45. rip_shout(p)
  46. void *p;
  47. {
  48.     register struct rip_list *rl;
  49.  
  50.     rl = (struct rip_list *)p;
  51.     stop_timer(&rl->rip_time);
  52.     send_routes(rl->dest,RIP_PORT,rl->flags&RIP_SPLIT,0,rl->flags&RIP_US);
  53.     set_timer(&rl->rip_time,rl->interval*1000L);
  54.     start_timer(&rl->rip_time);
  55. }
  56.  
  57. /* Send the routing table. */
  58. static void
  59. send_routes(dest,port,split,trig,us)
  60. int32 dest;             /* IP destination address to send to */
  61. int16 port;
  62. int split;              /* Do split horizon? */
  63. int trig;               /* Send only triggered updates? */
  64. int us;                 /* Include our address in update */
  65. {
  66.     char *cp;
  67.     int i,bits,numroutes,maxroutes;
  68.     int16 pktsize;
  69.     struct mbuf *bp;
  70.     struct route *rp;
  71.     struct socket lsock,fsock;
  72.     struct iface *iface;
  73.  
  74.     if((rp = rt_lookup(dest)) == NULLROUTE)
  75.         return; /* No route exists, can't do it */
  76.     iface = rp->iface;
  77.  
  78.     /* Compute maximum packet size and number of routes we can send */
  79.     pktsize = ip_mtu(dest) - IPLEN;
  80.     pktsize = min(pktsize,MAXRIPPACKET);
  81.     maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
  82.  
  83.     lsock.address = INADDR_ANY;
  84.     lsock.port = RIP_PORT;
  85.     fsock.address = dest;
  86.     fsock.port = port;
  87.  
  88.     /* Allocate space for a full size RIP packet and generate header */
  89.     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  90.         return;
  91.     numroutes = 0;
  92.     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  93.  
  94.     /* Emit route to ourselves, if requested */
  95.     if(us){
  96.         cp = putentry(cp,RIP_IPFAM,iface->addr,0);
  97.         numroutes++;
  98.     }
  99.     /* Emit default route, if appropriate */
  100.     if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)
  101.      && (!trig || (R_default.flags & RTTRIG))){
  102.         if(!split || iface != R_default.iface){
  103.             cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
  104.             numroutes++;
  105.         } else if(trig){
  106.             cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
  107.             numroutes++;
  108.         }
  109.     }
  110.     for(bits=0;bits<32;bits++){
  111.         for(i=0;i<HASHMOD;i++){
  112.             for(rp = Routes[bits][i];rp != NULLROUTE;rp=rp->next){
  113.                 if((rp->flags & RTPRIVATE)
  114.                  || (trig && !(rp->flags & RTTRIG)))
  115.                     continue;
  116.  
  117.                 if(numroutes >= maxroutes){
  118.                     /* Packet full, flush and make another */
  119.                     bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  120.                     send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  121.                     Rip_stat.output++;
  122.                     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  123.                         return;
  124.                     numroutes = 0;
  125.                     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  126.                 }
  127.                 if(!split || iface != rp->iface){
  128.                     cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric);
  129.                     numroutes++;
  130.                 } else if(trig){
  131.                     cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
  132.                     numroutes++;
  133.                 }
  134.             }
  135.         }
  136.     }
  137.     if(numroutes != 0){
  138.         bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  139.         send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  140.         Rip_stat.output++;
  141.     } else {
  142.         free_p(bp);
  143.     }
  144. }
  145. /* Add an entry to the rip broadcast list */
  146. int
  147. rip_add(dest,interval,flags)
  148. int32 dest;
  149. int32 interval;
  150. char flags;
  151. {
  152.     register struct rip_list *rl;
  153.     struct route *rp;
  154.  
  155.     if((rp = rt_lookup(dest)) == NULLROUTE){
  156.         printf("%s is unreachable\n",inet_ntoa(dest));
  157.         return 1;
  158.     }
  159.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  160.         if(rl->dest == dest)
  161.             break;
  162.  
  163.     if(rl == NULLRL){
  164.         /* get a chunk of memory for the rip interface descriptor */
  165.         rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  166.  
  167.         /* tack this record on as the first in the list */
  168.         rl->next = Rip_list;
  169.         if(rl->next != NULLRL)
  170.             rl->next->prev = rl;
  171.         Rip_list = rl;
  172.         rl->dest = dest;
  173.     }
  174.     /* and the interface ptr, tick interval and flags */
  175.     rl->iface = rp->iface;
  176.     rl->interval = interval;
  177.     rl->flags = flags;
  178.  
  179.     /* set up the timer stuff */
  180.     rl->rip_time.func = rip_shout;
  181.     rl->rip_time.arg = rl;
  182.     /* This will initialize the timer and do an immediate broadcast */
  183.     rip_shout(rl);
  184.     return 0;
  185. }
  186.  
  187. /* add a gateway to the rip_refuse list which allows us to ignore their
  188.  * advertisements
  189. */
  190. int
  191. riprefadd(gateway)
  192. int32 gateway;
  193. {
  194.     register struct rip_refuse *rl;
  195.  
  196.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  197.         if(rl->target == gateway)
  198.             return 0;       /* Already in table */
  199.  
  200.     /* get a chunk of memory for the rip interface descriptor */
  201.     rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  202.  
  203.     /* tack this record on as the first in the list */
  204.     rl->next = Rip_refuse;
  205.     if(rl->next != NULLREF)
  206.         rl->next->prev = rl;
  207.     Rip_refuse = rl;
  208.  
  209.     /* fill in the gateway to ignore */
  210.     rl->target = gateway;
  211.     return 0;
  212. }
  213.  
  214. /* drop a RIP target */
  215. int
  216. rip_drop(dest)
  217. int32   dest;
  218. {
  219.     register struct rip_list *rl;
  220.  
  221.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  222.         if(rl->dest == dest)
  223.             break;
  224.  
  225.     /* leave if we didn't find it */
  226.     if(rl == NULLRL)
  227.         return 0;
  228.  
  229.     /* stop the timer */
  230.     stop_timer(&rl->rip_time);
  231.  
  232.     /* Unlink from list */
  233.     if(rl->next != NULLRL)
  234.         rl->next->prev = rl->prev;
  235.     if(rl->prev != NULLRL)
  236.         rl->prev->next = rl->next;
  237.     else
  238.         Rip_list = rl->next;
  239.  
  240.     /* and deallocate the descriptor memory */
  241.     free((char *)rl);
  242.     return 0;
  243. }
  244.  
  245. /* drop a RIP-refuse target from the rip_refuse list */
  246. int
  247. riprefdrop(gateway)
  248. int32 gateway;
  249. {
  250.     register struct rip_refuse *rl;
  251.  
  252.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  253.         if(rl->target == gateway)
  254.             break;
  255.  
  256.     /* leave if we didn't find it */
  257.     if(rl == NULLREF)
  258.         return 0;
  259.  
  260.     /* Unlink from list */
  261.     if(rl->next != NULLREF)
  262.         rl->next->prev = rl->prev;
  263.     if(rl->prev != NULLREF)
  264.         rl->prev->next = rl->next;
  265.     else
  266.         Rip_refuse = rl->next;
  267.  
  268.     /* and deallocate the structure memory */
  269.     free((char *)rl);
  270.     return 0;
  271. }
  272.  
  273. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  274. void
  275. rip_trigger()
  276. {
  277.     register struct rip_list *rl;
  278.     int bits,i;
  279.     struct route *rp;
  280.  
  281.     for(rl=Rip_list;rl != NULLRL;rl = rl->next){
  282.         send_routes(rl->dest,RIP_PORT,(rl->flags & RIP_SPLIT),1,0);
  283.     }
  284.     /* Clear the trigger list */
  285.     R_default.flags &= ~RTTRIG;
  286.     for(bits=0;bits<32;bits++){
  287.         for(i=0;i<HASHMOD;i++){
  288.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  289.                 rp->flags &= ~RTTRIG;
  290.             }
  291.         }
  292.     }
  293. }
  294.  
  295. /* Start RIP agent listening at local RIP UDP port */
  296. int
  297. rip_init()
  298. {
  299.     struct socket lsock;
  300.  
  301.     lsock.address = INADDR_ANY;
  302.     lsock.port = RIP_PORT;
  303.  
  304.     if(Rip_cb == NULLUDP)
  305.         Rip_cb = open_udp(&lsock,rip_rx);
  306.  
  307.     return 0;
  308. }
  309.  
  310. /* Process RIP input received from 'interface'. */
  311. static void
  312. rip_rx(iface,sock,cnt)
  313. struct iface *iface;
  314. struct udp_cb *sock;
  315. int cnt;
  316. {
  317.     struct mbuf *bp;
  318.     struct socket fsock;
  319.     int cmd;
  320.     register struct rip_refuse *rfl;
  321.     struct rip_route entry;
  322.     struct route *rp;
  323.     struct rip_list *rl;
  324.     int32 ttl;
  325.  
  326.     /* receive the RIP packet */
  327.     recv_udp(sock,&fsock,&bp);
  328.  
  329.     /* increment the rcvd cnt */
  330.     Rip_stat.rcvd++;
  331.  
  332.     /* check the gateway of this packet against the rip_refuse list and
  333.      * discard it if a match is found
  334.      */
  335.     for(rfl=Rip_refuse;rfl != NULLREF;rfl = rfl->next){
  336.         if(fsock.address == rfl->target){
  337.             Rip_stat.refusals++;
  338.             if(Rip_trace > 1)
  339.                 printf("RIP refused from %s\n",
  340.                  inet_ntoa(fsock.address));
  341.             free_p(bp);
  342.             return;
  343.          }
  344.     }
  345.     cmd = PULLCHAR(&bp);
  346.     /* Check the version of the frame */
  347.     if(PULLCHAR(&bp) != RIPVERSION){
  348.         free_p(bp);
  349.         Rip_stat.version++;
  350.         return;
  351.     }
  352.     switch(cmd){
  353.     case RIPCMD_RESPONSE:
  354.         if(Rip_trace > 1)
  355.             printf("RIPCMD_RESPONSE from %s \n",inet_ntoa(fsock.address));
  356.  
  357.         Rip_stat.response++;
  358.         /* See if this interface is on our broadcast list; if so,
  359.          * use its interval to calculate entry lifetimes. Otherwise,
  360.          * use default
  361.          */
  362.         ttl = RIP_TTL;
  363.         for(rl=Rip_list; rl != NULLRL; rl = rl->next){
  364.             if(rl->iface == iface){
  365.                 ttl = rl->interval * 4;
  366.                 break;
  367.             }
  368.         }
  369.         (void)pull16(&bp);      /* remove one word of padding */
  370.         while(len_p(bp) >= RIPROUTE){
  371.             pullentry(&entry,&bp);
  372.             proc_rip(iface,fsock.address,&entry,ttl);
  373.         }
  374.         /* If we can't reach the sender of this update, or if
  375.          * our existing route is not through the interface we
  376.          * got this update on, add him as a host specific entry
  377.          */
  378.         if((rp = rt_blookup(fsock.address,32)) != NULLROUTE){
  379.             /* Host-specific route already exists, refresh it */
  380.             start_timer(&rp->timer);
  381.         } else if((rp = rt_lookup(fsock.address)) == NULLROUTE
  382.          || rp->iface != iface){
  383.             entry.addr_fam = RIP_IPFAM;
  384.             entry.target = fsock.address;
  385.             entry.metric = 0; /* will get incremented to 1 */
  386.             proc_rip(iface,fsock.address,&entry,ttl);
  387.         }
  388.         if(Rip_merge)
  389.             rt_merge(Rip_trace);
  390.         rip_trigger();
  391.         break;
  392.     case RIPCMD_REQUEST:
  393.         if(Rip_trace > 1)
  394.             printf("RIPCMD_REQUEST\n");
  395.  
  396.         Rip_stat.request++;
  397.         /* For now, just send the whole table with split horizon
  398.          * enabled when the source port is RIP_PORT, and send
  399.          * the whole table with split horizon disable when another
  400.          * source port is used. This should be replaced with a more
  401.          * complete implementation that checks for non-global requests
  402.          */
  403.         if(fsock.port == RIP_PORT)
  404.             send_routes(fsock.address,fsock.port,1,0,1);
  405.         else
  406.             send_routes(fsock.address,fsock.port,0,0,1);
  407.         break;
  408.     default:
  409.         if(Rip_trace > 1)
  410.             printf("RIPCMD: Unknown Type\n");
  411.  
  412.         Rip_stat.unknown++;
  413.         break;
  414.     } /* switch */
  415.     free_p(bp);
  416. }
  417. /* Apply a set of heuristics for determining the number of significant bits
  418.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  419.  * include the address mask for each entry.
  420.  */
  421. int
  422. nbits(target)
  423. int32 target;
  424. {
  425.     int bits;
  426.  
  427.     if(target == 0)
  428.         return 0;       /* Special case: 0.0.0.0 is the default route */
  429.  
  430.     /* Check the host-part bytes of
  431.      * the address to check for byte-wide zeros
  432.      * which we'll consider to be subnet routes.
  433.      * e.g. 44.80.0.0 will be considered to be equal to 44.80/16
  434.      * whereas 44.80.1.0 will be considered to be 44.80.1/24
  435.      */
  436.     switch (hibyte(hiword(target)) >> 6) {
  437.     case 3: /* Class C address */
  438.         /*is it a host address ? i.e. are there any 1's in the
  439.          * host part ?
  440.          */
  441.         if(target & 0xff)
  442.             bits = 32;
  443.         else
  444.             bits = 24;
  445.         break;
  446.     case 2:  /* Class B address */
  447.         if(target & 0xff)
  448.             bits = 32;
  449.         else if(target & 0xff00)
  450.             bits = 24;
  451.         else
  452.             bits = 16;
  453.         break;
  454.     case 0:   /* Class A address */
  455.     case 1:
  456.         if(target & 0xff)
  457.             bits = 32;
  458.         else if(target & 0xff00)
  459.             bits = 24;
  460.         else if(target & 0xff0000)
  461.             bits = 16;
  462.         else
  463.             bits = 8;
  464.     }
  465.  
  466.     return bits;
  467. }
  468. /* Remove and process a RIP response entry from a packet */
  469. static void
  470. proc_rip(iface,gateway,ep,ttl)
  471. struct iface *iface;
  472. int32 gateway;
  473. register struct rip_route *ep;
  474. int32 ttl;
  475. {
  476.     unsigned int bits;
  477.     register struct route *rp;
  478.     int add = 0;    /* action flags */
  479.     int drop = 0;
  480.     int trigger = 0;
  481.  
  482.     if(ep->addr_fam != RIP_IPFAM) {
  483.         /* Skip non-IP addresses */
  484.         if(Rip_trace > 1)
  485.             printf("RIP_rx: Not an IP RIP packet !\n");
  486.         Rip_stat.addr_family++;
  487.         return;
  488.     }
  489.     /* Guess at the mask, since it's not explicit */
  490.     bits = nbits(ep->target);
  491.  
  492.     /* Don't ever add a route to myself through somebody! */
  493.     if(bits == 32 && ismyaddr(ep->target) != NULLIF){
  494.         if(Rip_trace > 1){
  495.             printf("route to self: %s %ld\n",
  496.              inet_ntoa(ep->target),ep->metric);
  497.         }
  498.         return;
  499.     }
  500.     /* Update metric to reflect link cost */
  501.     ep->metric++;
  502.     ep->metric = min(ep->metric,RIP_INFINITY);
  503.  
  504.     /* Find existing entry, if any */
  505.     rp = rt_blookup(ep->target,bits);
  506.  
  507.     /* Don't touch private routes */
  508.     if(rp != NULLROUTE && (rp->flags & RTPRIVATE))
  509.         return;
  510.  
  511.     if(rp == NULLROUTE){
  512.         if(ep->metric < RIP_INFINITY){
  513.             /* New route; add it and trigger an update */
  514.             add++;
  515.             trigger++;
  516.         }
  517.     } else if(rp->metric == RIP_INFINITY){
  518.         /* Route is in hold-down; ignore this guy */
  519.         if(Rip_trace > 0){
  520.             printf("ignored (hold-down): %s %lu\n",
  521.              inet_ntoa(ep->target),ep->metric);
  522.         }
  523.     } else if(rp->gateway == gateway && rp->iface == iface){
  524.         /* This is the gateway for the entry we already have;
  525.          * restart the timer
  526.          */
  527.         set_timer(&rp->timer,ttl*1000L);
  528.         start_timer(&rp->timer);
  529.         if(rp->metric != ep->metric){
  530.             /* Metric has changed. Update it and trigger an
  531.              * update. If route has become unavailable, start
  532.              * the hold-down timeout.
  533.              */
  534.             if(Rip_trace){
  535.                 printf("metric change: %s %lu -> %lu\n",
  536.                  inet_ntoa(ep->target),rp->metric,ep->metric);
  537.             }
  538.             if(ep->metric == RIP_INFINITY)
  539.                 rt_timeout(rp); /* Enter hold-down timeout */
  540.             else
  541.                 rp->metric = ep->metric;
  542.             trigger++;
  543.         }
  544.     } else {
  545.         /* Entry is from a different gateway than the current route */
  546.         if(ep->metric < rp->metric){
  547.             /* Switch to a new gateway */
  548.             if(Rip_trace > 0){
  549.                 printf("metric better: %s %lu\n",
  550.                  inet_ntoa(ep->target),ep->metric);
  551.             }
  552.             drop++;
  553.             add++;
  554.             trigger++;
  555.         } else {
  556.             /* Metric is no better, stay with current route */
  557.             if(Rip_trace > 1){
  558.                 printf("metric not better: %s %lu\n",
  559.                  inet_ntoa(ep->target),ep->metric);
  560.             }
  561.         }
  562.     }
  563.     if(drop){
  564.         /* Switching to a better gateway; delete old entry */
  565.         if(Rip_trace){
  566.             printf("route drop [%s]/%u",
  567.              inet_ntoa(ep->target),bits);
  568.             if(rp != NULLROUTE)
  569.                 printf(" %s %s %lu",rp->iface->name,
  570.                  inet_ntoa(rp->gateway),rp->metric);
  571.             printf("\n");
  572.         }
  573.         rt_drop(ep->target,bits);
  574.     }
  575.     if(add){
  576.         /* Add a new entry */
  577.         if(Rip_trace > 0){
  578.             printf("route add [%s]/%u %s",inet_ntoa(ep->target),
  579.              bits,iface->name);
  580.             printf(" [%s] %u\n",inet_ntoa(gateway),
  581.              (int)ep->metric);
  582.         }
  583.         rp = rt_add(ep->target,(unsigned) bits,gateway,iface,
  584.          (int) ep->metric,ttl,0);
  585.     }
  586.     /* If the route changed, mark it for a triggered update */
  587.     if(trigger){
  588.         rp->flags |= RTTRIG;
  589.     }
  590. }
  591. /* Send a RIP request packet to the specified destination */
  592. int
  593. ripreq(dest,replyport)
  594. int32 dest;
  595. int16 replyport;
  596. {
  597.     struct mbuf *bp;
  598.     struct socket lsock,fsock;
  599.     char *cp;
  600.  
  601.     lsock.address = INADDR_ANY;
  602.     lsock.port = replyport;
  603.  
  604.     /* if we were given a valid dest addr, ask it (the routers on that net)
  605.      * for a default gateway
  606.      */
  607.     if(dest == 0)
  608.         return 0;
  609.  
  610.     fsock.address = dest;
  611.     fsock.port = RIP_PORT;
  612.  
  613.     /* Send out one RIP Request packet as a broadcast to 'dest'  */
  614.     if((bp = alloc_mbuf(RIPHEADER + RIPROUTE)) == NULLBUF)
  615.         return -1;
  616.  
  617.     cp = putheader(bp->data,RIPCMD_REQUEST,RIPVERSION);
  618.     cp = putentry(cp,0,0L,RIP_INFINITY);
  619.     bp->cnt = RIPHEADER + RIPROUTE;
  620.     send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  621.     Rip_stat.output++;
  622.     return 0;
  623. }
  624. void
  625. pullentry(ep,bpp)
  626. register struct rip_route *ep;
  627. struct mbuf **bpp;
  628. {
  629.     ep->addr_fam = pull16(bpp);
  630.     (void)pull16(bpp);
  631.     ep->target = pull32(bpp);
  632.     (void)pull32(bpp);
  633.     (void)pull32(bpp);
  634.     ep->metric = pull32(bpp);
  635. }
  636.  
  637. /* Write the header of a RIP packet */
  638. static char *
  639. putheader(cp,command,version)
  640. register char *cp;
  641. char command;
  642. char version;
  643. {
  644.     *cp++ = command;
  645.     *cp++ = version;
  646.     return put16(cp,0);
  647. }
  648.  
  649. /* Write a single entry into a rip packet */
  650. static char *
  651. putentry(cp,fam,target,metric)
  652. register char *cp;
  653. int16 fam;
  654. int32 target;
  655. int32 metric;
  656. {
  657.     cp = put16(cp,fam);
  658.     cp = put16(cp,0);
  659.     cp = put32(cp,target);
  660.     cp = put32(cp,0L);
  661.     cp = put32(cp,0L);
  662.     return put32(cp,metric);
  663. }
  664. /* Route timeout handler. If route has already been marked for deletion
  665.  * then delete it. Otherwise mark for deletion and restart timer.
  666.  */
  667. void
  668. rt_timeout(s)
  669. void *s;
  670. {
  671.     register struct route *rp = (struct route *)s;
  672.  
  673.     stop_timer(&rp->timer);
  674.     if(rp->metric < RIP_INFINITY){
  675.         rp->metric = RIP_INFINITY;
  676.         if(dur_timer(&rp->timer) == 0)
  677.             set_timer(&rp->timer,RIP_TTL*1000L);
  678.         /* wait 2/3 of timeout before garbage collect */
  679.         set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  680.         rp->timer.func = rt_timeout;
  681.         rp->timer.arg = (void *)rp;
  682.         start_timer(&rp->timer);
  683.         /* Route changed; mark it for triggered update */
  684.         rp->flags |= RTTRIG;
  685.         rip_trigger();
  686.     } else {
  687.         rt_drop(rp->target,rp->bits);
  688.     }
  689. }
  690.